using System;
using System.Web.Mvc;
using Stimulus360.Services;
using System.Globalization;
using Stimulus360.Models.Data;
using System.Web.Configuration;
using System.Collections.Generic;
using Stimulus360.Controllers.Ideas;
using Stimulus360.Services.Interfaces;
using Stimulus360.Models.Data.CustomTypes;

namespace Stimulus360.Controllers
{
    [HandleError]
    public class IdeasController : Controller
    {
        /// <summary>
        ///     Instance of IdeaService to be used
        /// </summary>
        private readonly IIdeaService _ideaService;

        /// <summary>
        ///     Instance of InvestmentCategoryService to be used
        /// </summary>
        private readonly IInvestmentCategoryService _investmentCategoryService;

        /// <summary>
        ///     The number ideas being shown in the screen
        /// </summary>
        private readonly string _pageSize = WebConfigurationManager.AppSettings["PageSize"];

        /// <summary>
        ///     Default Constructor. Instantiates the default services
        /// </summary>
        public IdeasController()
            : this(new IdeaService(), new InvestmentCategoryService())
        {
        }

        /// <summary>
        ///     Overloaded constructor to allow Dependency Injection.
        /// </summary>
        /// <param name="ideaService">
        ///     The Idea Service instance to be used
        /// </param>
        /// <param name="investmentCategoryService">
        ///     The InvestmentCategoryService to be used.
        /// </param>
        public IdeasController(IIdeaService ideaService, IInvestmentCategoryService investmentCategoryService)
        {
            _ideaService = ideaService ?? new IdeaService();
            _investmentCategoryService = investmentCategoryService ?? new InvestmentCategoryService();
        }

        /// <summary>
        ///     Method to return a list of New Ideas
        /// </summary>
        /// <param name="page">
        ///     Current Page No
        /// </param>
        /// <returns>
        ///     ViewModel containing list of new Ideas.
        /// </returns>
        public ActionResult Index(int? page)
        {
            NewIdeasListingViewModel model = new NewIdeasListingViewModel
                                                   {
                                                       Ideas = _ideaService.GetNew(page.GetValueOrDefault(0).ToString(CultureInfo.CurrentCulture), _pageSize),
                                                       Categories = _investmentCategoryService.GetAll()
                                                   };

            return View(model);
        }

        /// <summary>
        ///     Method to return details of the Idea
        /// </summary>
        /// <param name="ideaId">
        ///     IdeaId for which details are required
        /// </param>
        /// <returns>
        ///     ViewModel containing Idea Details
        /// </returns>
        public ActionResult Details(int ideaId)
        {
            Idea idea = _ideaService.FindById(ideaId.ToString(CultureInfo.CurrentCulture));
            ICollection<ProjectSummary> projectSummaries = null;
            if (idea.Status == (byte)IdeaStatus.Accepted)
            {
                projectSummaries = _ideaService.GetRelatedProjects(ideaId.ToString(CultureInfo.CurrentCulture));
            }
            IdeaDetailViewModel viewModel = new IdeaDetailViewModel
                                                {
                                                    Idea = idea,
                                                    IdeaProjectList = projectSummaries,
                                                    RelatedIdeas = _ideaService.GetRelated(ideaId.ToString(CultureInfo.CurrentCulture))
                                                };
            return View(viewModel);
        }

        /// <summary>
        ///     Method to return the list of feedback submitted for the given Idea
        /// </summary>
        /// <param name="ideaId">
        ///     IdeaId for which feedback is to  be retrieved.
        /// </param>
        /// <param name="page">
        ///     Current Page No. 
        /// </param>
        /// <returns>
        ///     ViewModel containing list of feedback for the given idea.
        /// </returns>
        public ActionResult Feedback(int ideaId, int? page)
        {
            Idea idea = _ideaService.FindById(ideaId.ToString(CultureInfo.CurrentCulture));
            IdeaFeedbackListingViewModel viewModel = new IdeaFeedbackListingViewModel
            {
                IdeaSummary = new IdeaSummary
                                  {
                                      IdeaId = ideaId,
                                      IdeaTitle = idea.Title,
                                      SubmittedDate = idea.DateSubmitted,
                                      Submitter = idea.SubmittedBy
                                  },
                Feedback = _ideaService.GetFeedback(ideaId.ToString(CultureInfo.CurrentCulture), page.GetValueOrDefault(0).ToString(CultureInfo.CurrentCulture), _pageSize)
            };
            return View(viewModel);
        }

        /// <summary>
        ///     GET method to add a new feedback
        /// </summary>
        /// <param name="ideaId">
        ///     IdeaId for which feedback will be added
        /// </param>
        /// <returns>
        ///      GET ViewModel for Add Feedback
        /// </returns>
        [Authorize]
        public ActionResult SubmitFeedback(int ideaId)
        {
            Idea idea = _ideaService.FindById(ideaId.ToString(CultureInfo.CurrentCulture));
            IdeaRating ideaRating ;

            bool alreadyPresent = false;
            IdeaRating originalRating = _ideaService.GetFeedback(User.Identity.Name, ideaId.ToString(CultureInfo.CurrentCulture));
            if (originalRating == null)
            {
                ideaRating = new IdeaRating { IdeaId = ideaId };
            }
            else
            {
                ideaRating = originalRating;
                alreadyPresent = true;
            }
            IdeaFeedbackSubmissionViewModel viewModel = new IdeaFeedbackSubmissionViewModel
                                                            {
                                                                IdeaSummary = GetIdeaSummary(idea),
                                                                AlreadySubmitted = alreadyPresent,
                                                                Feedback = ideaRating
                                                            };
            return View(viewModel);

        }

        /// <summary>
        ///     POST Method to Add feedback to the given Idea feedback .
        ///     It validates forgeryToken
        /// </summary>
        /// <param name="feedback">
        ///     The new feedback to be added
        /// </param>
        /// <returns>
        ///      ViewModel with new Feedback
        /// </returns>
        [ValidateAntiForgeryToken]
        [Authorize]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult SubmitFeedback(IdeaRating feedback)
        {

            Idea relatedIdea = _ideaService.FindById(feedback.IdeaId.ToString(CultureInfo.CurrentCulture));
            if (!feedback.IsValid)
            {
                ModelState.AddModelError(feedback.GetRuleViolations());
            }
            else
            {

                feedback.UserName = User.Identity.Name;
                feedback.DateSubmitted = DateTime.Now;
                _ideaService.AddFeedback(feedback);
                return RedirectToAction("Feedback", "Ideas", new { ideaId = feedback.IdeaId });

            }

            return View(new IdeaFeedbackSubmissionViewModel
                            {
                                IdeaSummary = GetIdeaSummary(relatedIdea),
                                Feedback = feedback
                            });
        }

        /// <summary>
        ///     Method to get the Idea Summary for an idea
        /// </summary>
        /// <param name="relatedIdea">
        ///     The idea under consideration
        /// </param>
        /// <returns>
        ///     The Idea summary
        /// </returns>
        private static IdeaSummary GetIdeaSummary(Idea relatedIdea)
        {
            return new IdeaSummary
                       {
                           IdeaTitle = relatedIdea.Title,
                           IdeaId = relatedIdea.IdeaId,
                           SubmittedDate = relatedIdea.DateSubmitted,
                           Submitter = relatedIdea.SubmittedBy
                       };
        }
        /// <summary>
        ///     Method return list of Ideas int he given category
        /// </summary>
        /// <param name="categoryTitle">
        ///     Category for which list of ideas is to be retrieved.
        /// </param>
        /// <param name="page">
        ///     Page No.of screen to be shown
        /// </param>
        /// <returns>
        ///     Returns ViewModel containing Ideas for the given category
        /// </returns>
        public ActionResult Category(string categoryTitle, int? page)
        {

            CategorizedIdeasListingViewModel model = new CategorizedIdeasListingViewModel
                                                           {
                                                               Categories = _investmentCategoryService.GetAll(),
                                                               Ideas = _ideaService.FindInCategory(categoryTitle, page.GetValueOrDefault(0).ToString(CultureInfo.CurrentCulture), _pageSize),
                                                               Category = categoryTitle
                                                           };
            return View(model);

        }

        /// <summary>
        ///     Method searches for Ideas based on the given criteria
        /// </summary>
        /// <param name="criteria">
        ///     Criteria can by date, top N or status
        /// </param>
        /// <param name="query">
        ///     Criteria string to be processed
        /// </param>
        /// <param name="page">
        ///      Page No. of the idea search page
        /// </param>
        /// <returns>
        ///     Returns search view
        /// </returns>
        public ActionResult Search(string criteria, string query, int? page)
        {
            IdeasSearchViewModel model = new IdeasSearchViewModel
               {
                   Ideas = _ideaService.Search(criteria, query, page.GetValueOrDefault(0).ToString(CultureInfo.CurrentCulture), _pageSize),
                   Categories = _investmentCategoryService.GetAll(),
                   SearchCriteria = criteria,
                   SearchString = query
               };
            return View(model);
        }

        /// <summary>
        ///     GET method to get the ViewModel for submitting a new Idea
        /// </summary>
        /// <returns>
        ///     Return new idea view Model
        /// </returns>
        [Authorize]
        public ActionResult New()
        {
            NewIdeaViewModel model = new NewIdeaViewModel
                                          {
                                              Categories = _investmentCategoryService.GetAll(),
                                              Idea = new Idea
                                                         {
                                                             SubmittedBy = User.Identity.Name,
                                                             DateSubmitted = DateTime.Now
                                                         }
                                          };

            return View(model);
        }

        /// <summary>
        ///   POST method to submit a new Idea
        /// </summary>
        /// <param name="idea">
        ///     New Idea to be added
        /// </param>
        /// <returns>
        ///     Returns new Idea view model
        /// </returns>
        [ValidateAntiForgeryToken]
        [Authorize]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult New(Idea idea)
        {
            if (!idea.IsValid)
                ModelState.AddModelError(idea.GetRuleViolations());

            if (ModelState.IsValid)
            {

                idea.SubmittedBy = User.Identity.Name;
                idea.DateSubmitted = DateTime.Now;

                _ideaService.Add(idea);
                return RedirectToAction("Details", "Ideas", new { ideaId = idea.IdeaId });

            }

            NewIdeaViewModel model = new NewIdeaViewModel
                                         {
                                             Categories = _investmentCategoryService.GetAll(),
                                             Idea = idea
                                         };
            return View(model);
        }

    }
}
